/*
 *    Copyright 2022 The DSMS Authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.dsms.common.util;

import com.dsms.common.prometheus.converter.Data;
import com.dsms.common.prometheus.converter.result.DefaultQueryResult;
import com.dsms.common.prometheus.converter.result.QueryDataType;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class PrometheusUtils {

    private PrometheusUtils() {
    }

    private static final Pattern NAMED_FORMAT_PATTERN = Pattern.compile("#\\{(?<key>.*?)}");

    public static String namedFormat(final String format, Map<String, ?> kvs) {
        final StringBuilder buffer = new StringBuilder();
        final Matcher match = NAMED_FORMAT_PATTERN.matcher(format);
        while (match.find()) {
            final String key = match.group("key");
            final Object value = kvs.get(key);
            if (value != null) {
                match.appendReplacement(buffer, value.toString());
            } else if (kvs.containsKey(key)) {
                match.appendReplacement(buffer, "null");
            } else {
                match.appendReplacement(buffer, "");
            }
        }
        match.appendTail(buffer);
        return buffer.toString();
    }

    private static QueryDataType searchDataType(String typeString) {
        for (QueryDataType each : QueryDataType.class.getEnumConstants()) {
            if (each.name().compareToIgnoreCase(typeString) == 0) {
                return each;
            }
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    public static <T extends Data> DefaultQueryResult<T> convertQueryResultString(String jsonString) {
        Gson gson = new GsonBuilder().registerTypeAdapter(DefaultQueryResult.class, new TypeAdapter<DefaultQueryResult<T>>() {
            @Override
            public void write(JsonWriter arg0, DefaultQueryResult<T> arg1) {
            }

            @Override
            public DefaultQueryResult<T> read(JsonReader reader) throws IOException {
                DefaultQueryResult<T> queryResult = new DefaultQueryResult<>();
                String status = null;
                String resultType = null;
                reader.beginObject();
                while (reader.hasNext()) {
                    String propertyName = reader.nextName();
                    if ("status".equals(propertyName)) {
                        status = reader.nextString();
                    } else if ("data".equals(propertyName)) {
                        reader.beginObject();
                        while (reader.hasNext()) {
                            propertyName = reader.nextName();
                            if ("resultType".equals(propertyName)) {
                                resultType = reader.nextString();
                            } else if ("result".equals(propertyName)) {
                                reader.beginArray();
                                while (reader.hasNext()) {
                                    queryResult.addData(Objects.requireNonNull(searchDataType(resultType)).convert(reader));
                                }
                                reader.endArray();
                            }
                        }
                        reader.endObject();
                    }
                }
                reader.endObject();
                queryResult.setStatus(status);
                queryResult.setResultType(resultType);
                return queryResult;
            }
        }).create();
        return gson.fromJson(jsonString, DefaultQueryResult.class);
    }

    /**
     * use args to replace "%s" in promQL
     */
    public static String getFormatPromQL(String promQL, String[] args) {
        return String.format(promQL, (Object[]) args);
    }
}
